package tcp

import (
	"alarm_service/common/client_conn"
	"alarm_service/common/logger"
	"alarm_service/internal/models"
	"alarm_service/internal/repo/command"
	"alarm_service/internal/repo/device"
	"bytes"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"strconv"
)

const (
	cmdDeviceElectricity      byte = 0x08
	cmdDeviceOxygen           byte = 0x05
	cmdDeviceWater            byte = 0x07
	cmdDeviceThreeElectricity byte = 0x03
	cmdDeviceTemperature      byte = 0x02
	cmdDeviceStandby          byte = 0x88
	cmdDeviceNetwork          byte = 0x16
	cmdDeviceMessage          byte = 0x09
	cmdDeviceICCID            byte = 0x10
	cmdDevicePhone            byte = 0x11
	cmdDeviceFlood            byte = 0x12
)

type DeviceInfoCase struct {
	deviceRepo device.Repo
	command.Repo
}

func NewDeviceInfoCase(dr device.Repo, cr command.Repo) *DeviceInfoCase {
	s := &DeviceInfoCase{
		Repo:       cr,
		deviceRepo: dr,
	}
	return s
}

func (s *DeviceInfoCase) Analysis(packet []byte, conn net.Conn) error {
	deviceInfo := models.Device{}
	deviceDetail := models.Device{}
	warnList := []string{}
	for i := 0; i < len(packet); {
		cmd := packet[i]
		size := 0
		switch cmd {
		case cmdDeviceElectricity:
			size = 1 + 1
			content := packet[i+1 : i+size]
			deviceInfo.DeviceElectricity = uint8(content[0])
		case cmdDeviceOxygen:
			size = 3 + 1
			content := packet[i+1 : i+size]
			deviceInfo.DeviceOxygen = uint8(content[0])
			deviceInfo.DeviceOxygenInfo = binary.BigEndian.Uint16(content[1:3])
		case cmdDeviceWater:
			size = 2 + 1
			content := packet[i+1 : i+size]
			deviceInfo.DeviceWater = binary.BigEndian.Uint16(content[0:2])
		case cmdDeviceThreeElectricity:
			size = 1 + 1
			content := packet[i+1 : i+size]
			deviceInfo.DeviceThreeElectricity = uint8(content[0])
		case cmdDeviceTemperature:
			size = 6 + 1
			content := packet[i+1 : i+size]
			temperature, err := strconv.ParseFloat(string(content[0:5]), 32)
			if err != nil {
				logger.Errorf("[Analysis] temperature 解析失败: %s , %v", string(content[0:5]), err)
				return errors.New("[Analysis] 解析失败")
			}
			deviceInfo.DeviceTemperature = float32(temperature)
			deviceInfo.DeviceHumidity = uint8(content[5])
		case cmdDeviceStandby:
			size = 1 + 1
			content := packet[i+1 : i+size]
			deviceInfo.DeviceStandby = uint8(content[0])
		case cmdDeviceNetwork:
			size = 1 + 1
			content := packet[i+1 : i+size]
			deviceInfo.DeviceStandby = uint8(content[0])
		case cmdDeviceMessage:
			size = 1 + 1
			content := packet[i+1 : i+size]
			deviceInfo.DeviceMessageSwitch = uint8(content[0])
		case cmdDeviceICCID:
			size = 18 + 1
			content := packet[i+1 : i+size]
			identifier := content[0:8]
			_deviceDetail, err := s.deviceRepo.GetDeviceByIdentifier(fmt.Sprintf("%x", identifier))
			if err != nil {
				logger.Errorf("[Analysis] unkonw device: %v", err)
				return errors.New("[Analysis]找不到设备")
			}
			client_conn.Set(conn, _deviceDetail.ID)
			deviceInfo.ID = _deviceDetail.ID
			deviceInfo.Identifier = _deviceDetail.Identifier
			deviceDetail.TemperatureLimit = _deviceDetail.TemperatureLimit
			deviceDetail.TemperatureLower = _deviceDetail.TemperatureLower
			deviceDetail.HumidityLimit = _deviceDetail.HumidityLimit
			deviceDetail.HumidityLower = _deviceDetail.HumidityLower
			deviceDetail.Outage = _deviceDetail.Outage
			deviceDetail.Hypoxia = _deviceDetail.Hypoxia
			deviceDetail.Flood = _deviceDetail.Flood
			deviceDetail.Temperature = _deviceDetail.Temperature
			deviceDetail.DeviceElectricity = _deviceDetail.DeviceElectricity
			deviceDetail.Call = _deviceDetail.Call
		case cmdDevicePhone:
			size = 1 + 1
			content := packet[i+1 : i+size]
			deviceInfo.DevicePhoneSwitch = uint8(content[0])
		case cmdDeviceFlood:
			size = 1 + 1
			content := packet[i+1 : i+size]
			deviceInfo.DeviceFlood = uint8(content[0])
		default:
			size = 1
			logger.Infof("[Analysis] unknow cmd: %x %x", cmd, packet)
			return errors.New("[Analysis]找不到协议")
		}
		i = i + size
	}
	deviceInfo.Status = models.DeviceStatusOnline
	// if deviceDetail.Outage {

	// }
	if deviceInfo.DeviceThreeElectricity == 1 {
		warnList = append(warnList, "三相电混乱报警")
	}
	if deviceInfo.DeviceThreeElectricity == 2 {
		warnList = append(warnList, "三相电缺项报警")
	}
	if deviceDetail.Outage {
		if deviceInfo.DeviceElectricity == 1 {
			warnList = append(warnList, "停电报警")
		}
	}
	if deviceDetail.Call {
		if deviceInfo.DeviceElectricity == 0 && deviceDetail.DeviceElectricity == 1 {
			warnList = append(warnList, "来电报警")
		}
	}
	if deviceDetail.Hypoxia {
		if deviceInfo.DeviceOxygen == 1 {
			warnList = append(warnList, "缺氧报警")
		}
	}
	if deviceDetail.Flood {
		if deviceInfo.DeviceFlood == 1 {
			warnList = append(warnList, "水浸报警")
		}
	}
	if deviceDetail.Temperature {
		if deviceDetail.TemperatureLimit != 0 {
			if deviceInfo.DeviceTemperature > deviceDetail.TemperatureLimit {
				warnList = append(warnList, "温度超过上限报警")
			}
		}
		if deviceDetail.TemperatureLower != 0 {
			if deviceInfo.DeviceTemperature < deviceDetail.TemperatureLower {
				warnList = append(warnList, "温度超过下限报警")
			}
		}
	}
	if deviceDetail.HumidityLimit != 0 {
		if deviceInfo.DeviceWater > deviceDetail.HumidityLimit {
			warnList = append(warnList, "湿度超过上限报警")
		}
	}
	if deviceDetail.HumidityLower != 0 {
		if deviceInfo.DeviceWater > deviceDetail.HumidityLower {
			warnList = append(warnList, "湿度超过下限报警")
		}
	}
	err := s.deviceRepo.SetDeviceByInfo(&deviceInfo)
	if err != nil {
		logger.Errorf("[Analysis] save deviceInfo: %v", err)
		return errors.New("[Analysis] save deviceInfo")
	}
	// 请求报警接口
	url := "http://127.0.0.1:3001/apitest/device/warn"
	data := map[string]interface{}{
		"identifier": deviceInfo.Identifier,
		"warnList":   warnList,
	}

	jsonData, err := json.Marshal(data)
	if err != nil {
		return nil
	}
	http.Post(url, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return nil
	}
	// defer resp.Body.Close()
	return nil
}

func (s *DeviceInfoCase) DeviceOffline(id int) error {
	s.deviceRepo.SetOffline(id)
	return nil
}
